/**
 * 
 */
package cn.jhz.filesharingsystem.dao;

import java.lang.reflect.ParameterizedType;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;

import cn.jhz.filesharingsystem.model.Pager;
import cn.jhz.filesharingsystem.model.SystemContext;

/**
 * BaseDao实现类,通过hibernate实现底层操作
  *  通过sessionFactory为每次数据库操作生成一个currentSession(会话).使用生成的会话完成数据库操作.
 * sessionFactory由Spring注入.
  *  通过getClazz()方法获取当前Dao实例的泛型, 以支持从数据库load()对象的操作.
 * @author asus
 * @param <T>
 */
public class BaseDaoImpl<T> implements BaseDao<T> {
	
	@Autowired
	private SessionFactory sessionFactory;
	
	private Class<?> clazz;
	/**
	  *  获取当前类(非BaseDaoImpl而是其子类)实体的直接超类的Class,由Type表示,通过getGenericSuperclass()方法
	 * (Type:是java中所有类型的通用超级接口,包括原始类型,参数化类型,数组类型,类型变量,和原始类型).
	  *  并将由Type表示的Class强转为ParameterizedType(表示一个参数化类型,如Collection<String>),通过该类的
	 * getActualTypeArguments()方法返回一个Type对象的数组,表示此类型的实际类型参数.取该Type数组的第一个元素
	 * (由于BaseDao及其实现类泛型参数只有一个所以取Type数组的第一个元素)
	 * @return
	 */
	private Class<?> getClazz(){
		if(clazz == null) {
			clazz = (Class<?>)(((ParameterizedType)(this.getClass().getGenericSuperclass())).getActualTypeArguments())[0];
		}
		return clazz;
	}
	
	/**
	  *   通过sessionFactory获取一个实时session
	 * @return
	 */
	private Session getSession() {
		return sessionFactory.getCurrentSession();
	}
	
	@Override
	public T add(T t) {
		getSession().save(t);
		return t;
	}

	@Override
	public void delete(int id) {
		getSession().delete(load(id));
	}

	@Override
	public void update(T t) {
		getSession().update(t);
	}

	@SuppressWarnings("unchecked")
	@Override
	public T load(int id) {
		return (T) getSession().load(getClazz(), id);
	}

	/**
	  * 查多条数据,用hql语句查询多条记录,没有分页,返回list结果集
	 * @param hql   hibernate基于对象的数据库查询语句
	 * @param objs  替换hql语句中?占位符的实参
	 * @param alias 替换hql语句中:name占位符的实参
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> list(String hql, Object[]objs, Map<String, Object> alias){
		
		hql = initSort(hql);
		Query<T> query = getSession().createQuery(hql);
		
		setParameter(query, objs); 
		setAliasParameter(query, alias);
		
		return query.list();
	}
	
	/**
	  *  查询多条数据,支持分页,返回结果封装在Pager<T>模型类
	 * @param hql   hibernate基于对象的数据库查询语句
	 * @param objs  替换hql语句中?占位符的实参
	 * @param alias 替换hql语句中:name占位符的实参
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Pager<T> find(String hql, Object[]objs, Map<String, Object> alias){
		
		Pager<T> pager = new Pager<>();
		/*为hql添加对查询结果进行排序的内容*/
		hql = initSort(hql);
		Query<T> query = getSession().createQuery(hql);
		
		/*设置查询属性*/
		setParameter(query, objs); 
		setAliasParameter(query, alias);
		setPager(query, pager);
		/*将查询结果列表放入pager*/
		pager.setRows(query.list());

		
		/*查询记录总条数,例如(select count(*) from users where id > 10)*/
		String countHql = getCountHql(hql);
		@SuppressWarnings("rawtypes")
		Query countQuery = getSession().createQuery(countHql);
		/*设置查询属性*/
		setParameter(countQuery, objs); 
		setAliasParameter(countQuery, alias);
		/*将查询结果数放入pager*/
		pager.setTotal((long) countQuery.uniqueResult());
		
		return pager;
	}
	
	/**
	  *  针对特殊查询,返回结果不受泛型制约
	 * @param hql
	 * @param objs
	 * @param alias
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Object queryByHql(String hql, Object[]objs, Map<String, Object> alias) {
		@SuppressWarnings("rawtypes")
		Query query = getSession().createQuery(hql);
		setParameter(query, objs); 
		setAliasParameter(query, alias);
		return query.uniqueResult();
	}
	
	/**
	  * 应对某些特殊情况,要用HQL更新
	 * @param hql
	 * @param objs
	 * @param alias
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void updateByHql(String hql, Object[]objs, Map<String, Object> alias) {
		Query query = getSession().createQuery(hql);
		setParameter(query, objs); 
		setAliasParameter(query, alias);
		query.executeUpdate();
	}
	
	
	
	/**
	  *  生成当前查询对象类型的总数的HQL查询语句
	 * @param hql
	 * @return
	 */
	private String getCountHql(String hql) {
		String hhql = hql.substring(hql.indexOf("FROM"));//获取hql后半部分
		String countHql = "SELECT COUNT(*)" + hhql;
		//hql语句,fetch
		countHql = countHql.replace("fetch", "");
		return countHql;
	}
	
	/**
	  * 设置查询起始页,以及查询数量
	 * @param query
	 * @param pager
	 */
	private void setPager(Query<T> query, Pager<T> pager) {
		Integer pageSize = SystemContext.getPageSize();
		Integer pageOffset = SystemContext.getPageOffset();
		
		if(pageOffset == null|| pageOffset < 0) {
				pageOffset = 0;  //pageOffset默认值
		}
		if(pageSize == null|| pageSize < 0) {
				pageSize = 10; //没有设置每页大小,默认每页显示10条
		}
			pager.setOffset(pageOffset);
			pager.setSize(pageSize);
			
			query.setFirstResult(pageOffset).setMaxResults(pageSize);	
	}

	/**
	  *  替换hql语句中:name(别名)占位符的实参
	 * @param query
	 * @param alias
	 */
	@SuppressWarnings("rawtypes")
	private void setAliasParameter(Query<T> query, Map<String, Object> alias) {
		// TODO Auto-generated method stub
		if(alias!=null) {
			Set<String> keys = alias.keySet();
			for (String key : keys) {
				Object val = alias.get(key);
				if(val instanceof Collection) {
					query.setParameterList(key, (Collection) val);
				}else {
					query.setParameter(key, val);
				}
			}
		}
	}

	/**
	  *  将hql里?占位符替换
	 * @param query
	 * @param objs
	 */
	private void setParameter(Query<T> query, Object[] objs) {
		if(objs!=null && objs.length > 0) {
			int index = 0;
			for(Object obj : objs) {
				query.setParameter(index++, obj);
			}
		}
		
	}

	/**
         *  给hql语句加排序规则
         *  排序规则在Controller中放入
	 * @param hql
	 * @return
	 */
	private String initSort(String hql) {
		String sort = SystemContext.getSort();    
		String order = SystemContext.getOrder();
		if(sort!=null && !"".equals(sort.trim())) {
			hql += " order by " + sort;
			if(!"desc".equals(order)) {
				hql += " asc";
			}else {
				hql += " desc";
			}
		}
		return hql;
	}
}
